package main

import (
	"errors"
	"fmt"
	"math"
	"reflect"
	"runtime"
)

type OpFunc func(int, int) int

func eval(op string, a, b int) (int, error) {
	switch op {
	case "+":
		return a + b, nil
	case "-":
		return a - b, nil
	case "*":
		return a * b, nil
	case "/":
		q, _ := div(a, b)
		return q, nil
	default:
		return -1,
			errors.New("unsupported operator: " + op)
	}
}

func div(a, b int) (q int, r int) {
	q = a / b
	r = a % b
	return
}

func sum(nums ...int) int {
	sum := 0
	for _, v := range nums {
		sum += v
	}
	return sum
}

func apply(op OpFunc, a, b int) int {
	opName := runtime.FuncForPC(
		reflect.ValueOf(op).Pointer()).Name()
	fmt.Printf("Calling function %s with args("+
		"%d, %d)\n", opName, a, b)
	return op(a, b)
}

func pow(a, b int) int {
	return int(math.Pow(float64(a), float64(b)))
}

func main() {
	if r, err := eval("+", 3, 4); err == nil {
		fmt.Println(r)
	}
	fmt.Println(
		apply(pow, 3, 4),
		apply(func(v1 int, v2 int) int {
			return int(math.Pow(float64(v1), float64(v2)))
		}, 3, 4))

}
